import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider;
import com.sun.net.httpserver.*;
import javax.net.ssl.*;
import java.io.*;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.PKCS8EncodedKeySpec;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.ocsp.*;
import org.bouncycastle.cert.ocsp.jcajce.JcaCertificateID;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.asn1.gm.GMObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.cert.ocsp.CertificateID;
import org.bouncycastle.cert.ocsp.OCSPException;
import org.bouncycastle.operator.DigestCalculator;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.operator.InputDecryptorProvider;
import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
import org.bouncycastle.pkcs.PKCSException;
import org.bouncycastle.pkcs.jcajce.JcePKCSPBEInputDecryptorProviderBuilder;
 import org.bouncycastle.jce.provider.BouncyCastleProvider;
 import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider;
import java.io.FileReader;
import java.security.PrivateKey;
import java.security.Security;
import java.io.*;
import java.math.BigInteger;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Date;

public class SM2HttpsServer {
    static {
     // 注册BC提供者（用于加密操作）
     Security.addProvider(new BouncyCastleProvider());
     // 注册BCJSSE提供者（用于TLS）
     Security.addProvider(new BouncyCastleJsseProvider());
    }

    public static void main(String[] args) throws Exception {
        int port = 443;
        
        // 1. 加载国密证书和私钥
        KeyStore keyStore = createKeyStore("rsa.crt", "rsa.key","ca.crt");
        
        // 2. 初始化KeyManagerFactory
        KeyManagerFactory kmf = KeyManagerFactory.getInstance("PKIX", "BCJSSE");
        kmf.init(keyStore, "password".toCharArray());

        TrustManagerFactory tmpkmf = TrustManagerFactory.getInstance("PKIX", "BCJSSE");
        tmpkmf.init(keyStore); 
        Provider bcJsseProvider = Security.getProvider("BCJSSE");
        if (bcJsseProvider != null) {
            System.out.println("\nBCJSSE Provider Services for SSLContext:");
            for (Provider.Service service : bcJsseProvider.getServices()) {
                if (service.getType().equals("SSLContext")) {
                    System.out.println("  Algorithm: " + service.getAlgorithm());
                }
            }
        } else {
            System.out.println("BCJSSE provider not found!");
        }
        // 3. 创建SSL上下文
        SSLContext sslContext = SSLContext.getInstance("TLS", "BCJSSE");
        sslContext.init(kmf.getKeyManagers(), tmpkmf.getTrustManagers(),null ); //new SecureRandom()
        
        // 4. 创建HTTPS服务器
        HttpsServer server = HttpsServer.create(new InetSocketAddress(port), 0);
        server.setHttpsConfigurator(new HttpsConfigurator(sslContext) {
            @Override
            public void configure(HttpsParameters params) {
                try {
                    SSLContext context = getSSLContext();
                    SSLParameters sslParams = context.getDefaultSSLParameters();
                    sslParams.setProtocols(new String[]{"TLSv1.3", "TLSv1.2"});
                   /* sslParams.setCipherSuites(
                        new String[]{"TLS_SM4_GCM_SM3", "TLS_SM4_CCM_SM3"}
                    );*/
                    params.setSSLParameters(sslParams);

                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        });
        
        // 5. 创建请求处理器
        server.createContext("/", exchange -> {
            String response = "国密HTTPS服务端已连接！";
            exchange.sendResponseHeaders(200, response.getBytes(StandardCharsets.UTF_8).length);
            try (OutputStream os = exchange.getResponseBody()) {
                os.write(response.getBytes(StandardCharsets.UTF_8));
            }
        });
        
        server.start();
        System.out.println("国密HTTPS服务端已启动，端口: " + port);
    }

    private static KeyStore createKeyStore(String certFile, String keyFile,String caFile) throws Exception {
        KeyStore keyStore = KeyStore.getInstance("PKCS12", "BC");
        keyStore.load(null, null);
        
        Certificate cert = loadCertificate(certFile);
        Certificate ca = loadCertificate(caFile);
        PrivateKey privateKey = loadPrivateKey(keyFile);
        //System.out.println("Hello",cert);
        keyStore.setKeyEntry("sm2-key", privateKey, "password".toCharArray(), 
            new Certificate[]{cert,ca});
        
        return keyStore;
    }

    private static Certificate loadCertificate(String filename) throws Exception {
        try (FileInputStream fis = new FileInputStream(filename)) {
            // 尝试PEM格式
            if (isPEMFile(filename)) {
                PEMParser parser = new PEMParser(new InputStreamReader(fis));
                Object obj = parser.readObject();
                if (obj instanceof X509CertificateHolder) {
                    return new JcaX509CertificateConverter()
                            .setProvider("BC")  // 使用BC提供程序
                            .getCertificate((X509CertificateHolder) obj);
                }
                throw new IOException("不支持的PEM格式: " + obj.getClass().getName());
            }
            
            // 尝试DER格式
            CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); // 使用BC提供程序
            return (X509Certificate) cf.generateCertificate(fis);
        }
    }
    // 检查文件是否为PEM格式
    private static boolean isPEMFile(String filename) {
        try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
            String firstLine = reader.readLine();
            return firstLine != null && firstLine.contains("-----BEGIN");
        } catch (IOException e) {
            return false;
        }
    }
    // 根据证书类型确定签名算法
    private static String getSignatureAlgorithm(X509Certificate cert) {
        String algorithm = cert.getSigAlgName();
        if (algorithm.contains("SM3")) {
            return "SM3withSM2";
        } else if (algorithm.contains("ECDSA")) {
            return "SHA256withECDSA";
        } else {
            return "SHA256withRSA";
        }
    }
    
    // 加载私钥 (支持PEM格式)
    private static PrivateKey loadPrivateKey(String filename) throws Exception {
        try (FileReader reader = new FileReader(filename)) {
            PEMParser parser = new PEMParser(reader);
            Object obj = parser.readObject();
            JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
            
            if (obj instanceof org.bouncycastle.openssl.PEMKeyPair) {
                // 处理传统RSA私钥 (PKCS#1格式)
                return converter.getPrivateKey(((org.bouncycastle.openssl.PEMKeyPair) obj).getPrivateKeyInfo());
            } else if (obj instanceof org.bouncycastle.asn1.pkcs.PrivateKeyInfo) {
                // 处理PKCS#8格式私钥
                return converter.getPrivateKey((org.bouncycastle.asn1.pkcs.PrivateKeyInfo) obj);
            } else if (obj instanceof org.bouncycastle.openssl.PEMEncryptedKeyPair) {
                throw new IOException("加密私钥需要密码");
            }
            
            // 尝试直接作为私钥对象处理
            if (obj instanceof PrivateKey) {
                return (PrivateKey) obj;
            }
            
            throw new IOException("不支持的私钥格式: " + (obj != null ? obj.getClass().getName() : "null"));
        }
    }

}